﻿using System;
using System.Diagnostics;

namespace Postnuclear.Dependency.Tree
  {
  /// <summary>
  /// Dependency base implementation for <see cref="INotifyValueChanged"/>.
  /// Provides notifications when the first ValueChanged event handler gets subscribed.
  /// When the last ValueChanged event handler gets unsubscribed, it will notify as well.
  /// </summary>
  /// <remarks>
  /// This class allows dependency element to unsubscribe from target objects when it is not listened anymore.
  /// It helps to avoid memory leaks when dependency tree is not listened to anymore.
  /// </remarks>
  internal abstract class NotifyValueChanged
    : INotifyValueChanged
    {
    #region Public

    // Events

    /// <summary>
    /// Occurs when the "value" of the instance is changed.
    /// </summary>
    public event EventHandler<EventArgs> ValueChanged
      {
      add
        {
        ValueChangedEventHandler += value;
        IsActive = ValueChangedEventHandler != null;
        }

      remove
        {
        ValueChangedEventHandler -= value;
        IsActive = ValueChangedEventHandler != null;
        }
      }

    #endregion

    #region Protected

    // Properties

    /// <summary>
    /// Gets a value indicating whether there are subscribers to this instance.
    /// </summary>
    /// <value>
    /// <c>true</c> if there are some subscribers; otherwise, <c>false</c>.
    /// </value>
    protected bool IsActive
      {
      get
        {
        return _isActive;
        }

      private set
        {
        if (value == _isActive)
          {
          return;
          }

        _isActive = value;
        OnIsActiveChanged();
        }
      }

    // Methods

    /// <summary>
    /// Called when when activation state is changed.
    /// </summary>
    protected abstract void OnIsActiveChanged();

    /// <summary>
    /// Raises the <see cref="ValueChanged"/> event.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    [DebuggerHidden]
    protected void RaiseValueChanged(object sender, EventArgs e)
      {
      ValueChangedEventHandler.Raise(sender, e);
      }

    #endregion

    #region Private

    // Properties

    private EventHandler<EventArgs> ValueChangedEventHandler
      {
      get;
      set;
      }

    // Fields

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private bool _isActive;

    #endregion
    }
  }